﻿using System;
using System.Collections.Generic;
using System.Text;
using ESRI.ArcGIS.ADF;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.Server;
using ESRI.ArcGIS.SystemUI;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Display;

namespace PlanningGIS.Framework
{
    /// <summary>
    /// 
    /// </summary>
    public class FeatureSnapClass :  ISnapAgent, IFeatureSnapAgent, IPersist, IPersistStream
    {
        IApplication m_Application = null;
        IEditor m_Editor = null;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="pApplicaton"></param>
        public FeatureSnapClass(IApplication pApplicaton)
        {
            m_Application = pApplicaton;
            // m_Editor=(m_Application as IFramework).Editor;
        }
        /// <summary>
        /// 
        /// </summary>
        private IFeatureCache m_FeatureCache = null;
        /// <summary>
        /// 
        /// </summary>
        public IFeatureCache FeatureCache { get { return m_FeatureCache; } }

        private IFeatureClass m_FeatureClass = null;
        /// <summary>
        /// 
        /// </summary>
        public IFeatureClass FeatureClass { get { return m_FeatureClass; } set { m_FeatureClass = value; } }

        private esriGeometryHitPartType m_HitPartType = esriGeometryHitPartType.esriGeometryPartNone;
        /// <summary>
        /// 
        /// </summary>
        public esriGeometryHitPartType HitType { get { return m_HitPartType; } set { m_HitPartType = value; } }

        private string m_SnapAgent_Name = String.Empty;
        /// <summary>
        /// 
        /// </summary>
        public string ISnapAgent_Name { get { return m_SnapAgent_Name; } }

        private bool m_ZSnappingEnabled = false;
        /// <summary>
        /// 
        /// </summary>
        public bool ZSnappingEnabled { get { return m_ZSnappingEnabled; } set { m_ZSnappingEnabled = value; } }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="inPoint"></param>
        /// <param name="outPoint"></param>
        /// <param name="tolerance"></param>
        /// <param name="distance"></param>
        /// <returns></returns>
        public bool Snap(IPoint inPoint, out IPoint outPoint, double tolerance, ref double distance)
        {
            outPoint = new PointClass();
            if (m_FeatureClass == null || m_Editor == null)
                return false;
            m_FeatureCache = new FeatureCache();
            bool bContain = m_FeatureCache.Contains(inPoint);
            if (!bContain)
            {
                FillCache(inPoint, tolerance);
            }
            double dbHitDistance = 0;
            int hitPartIndex = 0;
            int hitSegIndex = 0;
            bool bRightSide = false;
            bool bHitTest = false;

            double minDistance = double.MaxValue;
            for (int i = 0; i < m_FeatureCache.Count; i++)
            {
                IFeature pFeat = m_FeatureCache.get_Feature(i);

                IHitTest pHitTest = pFeat.Shape as IHitTest;
                IPoint pHitPnt = new PointClass();
                bHitTest = pHitTest.HitTest(inPoint, tolerance, m_HitPartType, pHitPnt, ref dbHitDistance, ref hitPartIndex, ref hitSegIndex, ref bRightSide);
                if (bHitTest)
                {
                    if (dbHitDistance < minDistance)
                    {
                        minDistance = dbHitDistance;
                        outPoint = pHitPnt;
                    }
                }
            }
            if (minDistance != double.MaxValue)
            {
                distance = minDistance;
                return true;
            }
            return false;
        }

        private void FillCache(IPoint pPoint, double Distance)
        {
            m_FeatureCache.Initialize(pPoint, Distance);
            m_FeatureCache.AddFeatures(this.m_FeatureClass);
        }


        private void GetFeatureClass()
        {
            IMap map = m_Editor.Map as IMap;
            IEditLayers snapLayers = m_Editor as IEditLayers;
            IFeatureLayer featLayer = snapLayers.CurrentLayer as IFeatureLayer;

            for (int CountLayers = 0; CountLayers < map.LayerCount; CountLayers++)
            {
                if (featLayer == null)
                    return;

                if (featLayer.FeatureClass.ShapeType != esriGeometryType.esriGeometryPoint)
                {
                    return;
                }
                else
                {
                    m_FeatureClass = featLayer.FeatureClass;
                }
            }
        }

        private string m_Name = null;
        /// <summary>
        /// 
        /// </summary>
        public string Name { get { return m_Name; } set { m_Name = value; } }


        #region ISnapAgentFeedback
        private string m_SnapText = null;
        /// <summary>
        /// 
        /// </summary>
        public string SnapText { get { return m_SnapText; } }
        #endregion

        #region IPersist,IPersistStream
        /// <summary>
        /// 
        /// </summary>
        /// <param name="pClassID"></param>
        public void GetClassID(out Guid pClassID)
        {
            pClassID = new System.Guid();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="pcbSize"></param>
        public void GetSizeMax(out _ULARGE_INTEGER pcbSize)
        {
            pcbSize = new _ULARGE_INTEGER();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="pClassID"></param>
        public void IPersistStream_GetClassID(out Guid pClassID)
        {
            pClassID = new System.Guid();
        }
        /// <summary>
        /// 
        /// </summary>
        public void IsDirty()
        {

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="Stream"></param>
        public void Load(IStream Stream)
        {
            if (Stream == null)
            {
                throw new System.ArgumentNullException("Stream");
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="Stream"></param>
        /// <param name="fClearDirty"></param>
        public void Save(IStream Stream, int fClearDirty)
        {
            if (Stream == null)
            {
                throw new System.ArgumentNullException("Stream");
            }
        }
        #endregion

        #region IObjectClassEvents
        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        public void OnChange(IObject obj)
        {

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        public void OnCreate(IObject obj)
        {

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        public void OnDelete(IObject obj)
        {

        }
        #endregion
    }
}
